package explorandum.f09.g5;

import explorandum.GameConstants;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

public class Features {
	public static final int    UNKNOWN  =   40;
	public static final int    MTN_PASS =   41;
	public static final int      BRIDGE =   42;
	public static final int  BODY_WATER =   43;
	
	public ArrayList<Feature> features;
	private Map map;
	
	
	Features(Map map) {
		this.features= new ArrayList<Feature>();
		this.map = map;
	}
	
	/*
	 * checkNewPoint:
	 * 	Inputs:  Point 'p', a new point that should be a cell that has non-land terrain, but not enforced
	 *  Outputs:   By analyzing the neighbors of 'p', we attempt to see if whether
	 *             this point is attached to any "feature" that we have seen.
	 *             
	 *             We may want to use this to update the map information, i.e. if a
	 *             water point we've already seen has been marked as new, but as we walk
	 *             towards it it appears that it has been claimed, we want to update
	 *             the functions to specify that the place is no longer interesting to us.
	 *             
	 *  Memo:  may want to generalize for mountains as well ...
	 */
	public Feature checkNewPoint(Point p) {
		Cell queryCell = map.getCell(p);
		
		// Only interesting if terrain isn't land; we'll see if we want to generalize to all features
		if(queryCell != null && queryCell.terrain != GameConstants.LAND) {
			/*  1. In theory, point is new, but check if already in features list.
			 *  2. Get neighbors, and check if they have same terrain and find the list of features ...
			 */
			
			for(Feature tmpFeat : features) {
				if(tmpFeat.hasCell(queryCell)) {
					/* We already have this cell in list */
					return tmpFeat;
				}
			}

			ArrayList<Cell> neighbors = map.getImmediateNeighbors(queryCell.location);
			ArrayList<Feature> foundFeatures = new ArrayList<Feature>();
			for(Cell neighbor : neighbors) {
				// If not the same terrain, then don't care about it being a feature
				if(neighbor != null && neighbor.terrain == queryCell.terrain) {
					for (Feature tmpFeat : features) {
						if(tmpFeat.hasCell(neighbor) && !foundFeatures.contains(tmpFeat)) {
							foundFeatures.add(tmpFeat);
						}
					}
				}
			}
			
			// We now have 3 choices.  Either foundFeatures has 0, 1, or more options
			//   if 0: create new
			//   if 1: add to current
			//   if +: merge into 1
			
			if(foundFeatures.size() == 0) {
				Feature newFeature = new Feature(queryCell.terrain);
				newFeature.addCell(queryCell);
				
				features.add(newFeature);
				
				return newFeature;
			}
			else if (foundFeatures.size() == 1) {
				foundFeatures.get(0).addCell(queryCell);
				return foundFeatures.get(0);
			}
			else if (foundFeatures.size() > 1) {
				Feature newFeature = new Feature(queryCell.terrain);
				for(Feature addendFeature : foundFeatures) {
					newFeature.addAll(addendFeature);
					features.remove(addendFeature);
				}
				newFeature.addCell(queryCell);
				features.add(newFeature);
				
				return newFeature;
			}
		}
	
		return null;
	}
	
	public Feature getFeatureByPoint(Point point) {
		Cell cell = map.getCell(point);
		for (Feature feat : this.features) {
			if(feat.cells.contains(cell)) {
				return feat;
			}
		}
		return null;
	}
}
